package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.dto.PageDTO;
import com.leyou.common.exceptions.LyException;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.item.dto.SpuDetailDTO;
import com.leyou.item.entity.*;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.leyou.common.constants.MQConstants.ExchangeConstants.ITEM_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.ITEM_DOWN_KEY;
import static com.leyou.common.constants.MQConstants.RoutingKeyConstants.ITEM_UP_KEY;

/**
 * @author 虎哥
 */
@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    private final BrandService brandService;
    private final CategoryService categoryService;
    private final SpuDetailService detailService;
    private final SkuService skuService;
    private final AmqpTemplate amqpTemplate;

    public SpuServiceImpl(BrandService brandService, CategoryService categoryService, SpuDetailService detailService, SkuService skuService, AmqpTemplate amqpTemplate) {
        this.brandService = brandService;
        this.categoryService = categoryService;
        this.detailService = detailService;
        this.skuService = skuService;
        this.amqpTemplate = amqpTemplate;
    }

    @Override
    public PageDTO<SpuDTO> querySpuByPage(
            Integer page, Integer rows, Boolean saleable, Long categoryId, Long brandId, Long id) {
        // 1.健壮性
        int current = Math.max(page, 1);
        int size = Math.max(rows, 5);

        // 2.准备查询条件， SELECT * FROM tb_spu WHERE saleable = ? AND category_id = ? AND brand_id = ? AND id = ?
        Page<Spu> result = query()
                .eq(saleable != null, "saleable", saleable)
                .eq(categoryId != null, "cid3", categoryId)
                .eq(brandId != null, "brand_id", brandId)
                .eq(id != null, "id", id)
                // 按照时间排序
                .orderByDesc("update_time")
                // 3.准备分页条件 LIMIT ?, ?
                .page(new Page<>(current, size));

        // 4.解析查询结果
        long total = result.getTotal();
        long pages = result.getPages();
        List<Spu> list = result.getRecords();

        // 5.转换DTO
        List<SpuDTO> dtoList = SpuDTO.convertEntityList(list);
        for (SpuDTO spuDTO : dtoList) {
            // 查询spu的分类和品牌的名称
            handleCategoryAndBrandName(spuDTO);
        }

        // 6.封装分页结果并返回
        return new PageDTO<>(total, pages, dtoList);
    }

    @Override
    @Transactional
    public void saveGoods(SpuDTO spuDTO) {
        // 1.新增Spu
        // 1.1.转换DTO到PO
        Spu spu = spuDTO.toEntity(Spu.class);
        // 1.2.默认下架
        spu.setSaleable(false);
        // 1.3.新增
        save(spu);

        Long spuId = spu.getId();
        // 2.新增SpuDetail
        SpuDetailDTO detailDTO = spuDTO.getSpuDetail();
        // 2.1.转换DTO到PO
        SpuDetail detail = detailDTO.toEntity(SpuDetail.class);
        // 2.2.补充数据
        detail.setSpuId(spuId);
        // 2.3.新增Detail
        detailService.save(detail);

        // 3.新增Sku
        // 3.1.取出sku
        List<SkuDTO> skuDTOList = spuDTO.getSkus();

        // 准备一个sku集合
        List<Sku> skuList = new ArrayList<>();
        for (SkuDTO skuDTO : skuDTOList) {
            // 3.2.转换DTO到PO
            Sku sku = skuDTO.toEntity(Sku.class);
            // 3.3.补充数据
            sku.setSpuId(spuId);
            sku.setSaleable(false);
            skuList.add(sku);
        }

        // 3.4.新增
        skuService.saveBatch(skuList);
    }

    @Transactional
    @Override
    public void updateSaleable(Long id, Boolean saleable) {
        // 更新spu中的saleable，update tb_spu set saleable = ? where id = ?
        Spu spu = new Spu();
        spu.setId(id);
        spu.setSaleable(saleable);
        boolean success = updateById(spu);
        if(!success){
            throw new LyException(500, "更新上下架失败！");
        }
        // 更新sku中的saleable，update tb_sku set saleable = ? where spu_id = ?
        success = skuService.update().set("saleable", saleable).eq("spu_id", id).update();
        if(!success){
            throw new LyException(500, "更新上下架失败！");
        }

        // 发送MQ消息，通知商品的上下架情况
        String routingKey = saleable ? ITEM_UP_KEY : ITEM_DOWN_KEY;
        amqpTemplate.convertAndSend(ITEM_EXCHANGE_NAME, routingKey, id);
    }

    @Override
    public SpuDTO queryGoodsById(Long id) {
        // 1.查询spu
        Spu spu = getById(id);
        if(spu == null){
            // 没有查询到，直接返回404
            throw new LyException(404, "商品不存在！");
        }
        SpuDTO spuDTO = new SpuDTO(spu);

        // 2.查询Detail
        SpuDetail detail = detailService.getById(id);
        spuDTO.setSpuDetail(new SpuDetailDTO(detail));

        // 3.查询sku
        List<Sku> skuList = skuService.query().eq("spu_id", id).list();
        spuDTO.setSkus(SkuDTO.convertEntityList(skuList));

        // 4.处理分类和品牌名称
        handleCategoryAndBrandName(spuDTO);
        return spuDTO;
    }

    @Transactional
    @Override
    public void updateGoods(SpuDTO spuDTO) {
        // 1.修改spu
        // 1.1.判断是否包含spu信息
        if (spuDTO.getId() != null) {
            // 1.2.如果有，则修改
            Spu spu = spuDTO.toEntity(Spu.class);
            boolean success = updateById(spu);
            if(!success){
                throw new LyException(500, "更新商品失败！");
            }
        }
        // 2.修改Detail
        // 2.1.判断是否包含spuDetail信息
        if (spuDTO.getSpuDetail() != null) {
            // 2.2.如果有，则修改
            SpuDetail detail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);
            boolean success = detailService.updateById(detail);
            if(!success){
                throw new LyException(500, "更新商品失败！");
            }
        }


        // 3.修改Sku
        List<SkuDTO> skuDTOList = spuDTO.getSkus();
        if(CollectionUtils.isEmpty(skuDTOList)){
            // 没有，直接结束
            return;
        }
        // 3.1.判断是否包含saleable字段，包含说明需要删除
        // 目的是把要删除的sku，和新增修改的sku分离
        Map<Boolean, List<Sku>> map = skuDTOList.stream() // SkuDTO的流
                .map(skuDTO -> skuDTO.toEntity(Sku.class)) // SkuDTO -- > Sku的流
                .collect(Collectors.groupingBy(sku -> sku.getSaleable() == null));

        // 3.2.判断是否有需要删除的，如果有则删除
        List<Sku> deleteSkuList = map.get(false);
        // 3.2.1.判断是否为空
        if(!CollectionUtils.isEmpty(deleteSkuList)){
            // 3.2.2.删除，获取sku的id集合
            List<Long> idList = deleteSkuList.stream().map(Sku::getId).collect(Collectors.toList());
            // 3.2.3.批量删除
            skuService.removeByIds(idList);
        }

        // 3.3.判断是否有需要新增的，如果有新增
        List<Sku> insertOrUpdateSkuList = map.get(true);
        // 3.3.1.判断是否为空
        if(!CollectionUtils.isEmpty(insertOrUpdateSkuList)){
            // 3.3.2.批量新增或修改
            skuService.saveOrUpdateBatch(insertOrUpdateSkuList);
        }
    }

    private void handleCategoryAndBrandName(SpuDTO spuDTO) {
        // 根据品牌id查询品牌名称
        Brand brand = brandService.getById(spuDTO.getBrandId());
        if(brand != null) {
            spuDTO.setBrandName(brand.getName());
        }
        // 根据三级分类id查询分类集合
        List<Category> categories = categoryService.listByIds(spuDTO.getCategoryIds());
        if(!CollectionUtils.isEmpty(categories)) {
            // 取出分类的名称，拼接起来
            String names = categories.stream().map(Category::getName).collect(Collectors.joining("/"));
            spuDTO.setCategoryName(names);
        }
    }
}
